package com.wanwu.channel.service.strategy;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.google.common.base.Strings;
import com.wanwu.channel.common.enums.*;
import com.wanwu.channel.common.exception.SystemException;
import com.wanwu.channel.common.util.AmountUtil;
import com.wanwu.channel.common.util.DateUtils;
import com.wanwu.channel.core.enums.AliPayTradeStatusEnum;
import com.wanwu.channel.dao.entity.ChannelMerchantInfoEntity;
import com.wanwu.channel.dao.entity.ChannelRefundEntity;
import com.wanwu.channel.dto.vo.*;
import com.wanwu.channel.remote.alipay.config.AlipayConfiguration;
import com.wanwu.channel.service.strategy.domain.*;
import com.wanwu.channel.tools.DingAlarmTool;
import com.wanwu.channel.core.tool.AlarmPoolUtil;
import com.wanwu.monitor.api.util.vo.AlarmMsgVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * created by xiaowei 2020-04-21
 * 支付宝 app 支付 + 报关
 */
@Component
public class AlipayAppPayStrategy implements PayStrategy {

    private static Logger logger = LoggerFactory.getLogger(AlipayAppPayStrategy.class);

    private static ConcurrentHashMap<String, DefaultAlipayClient> clientMap = new ConcurrentHashMap<>();

    public static final String CHARSET_UTF8 = "UTF-8";

    public static final String SIGN_TYPE = "RSA2";

    public static final String FORMAT_JSON = "json";

    @Autowired
    private AlipayConfiguration alipayConfiguration;

    @Resource
    private DingAlarmTool dingAlarmTool;

    private DefaultAlipayClient alipayClient;

    /**
     * 老的配置还是走老的配置文件内容
     */
    @Resource
    private AlarmPoolUtil alarmPoolUtil;

    @Value("${mq.ding.appKey}")
    private String dingKey;

    @PostConstruct
    public void init() {
        alipayClient = new DefaultAlipayClient(alipayConfiguration.getOpenApiDomain(), alipayConfiguration.getAppid(), alipayConfiguration.getQdPrivateKey(), FORMAT_JSON, CHARSET_UTF8, alipayConfiguration.getAlipayPublicKey(), SIGN_TYPE);
        alipayClient.setConnectTimeout(alipayConfiguration.getConnectTimeout());
        alipayClient.setReadTimeout(alipayConfiguration.getReadTimeout());
    }

    private DefaultAlipayClient initClient(ChannelMerchantInfoEntity entity) {
        if (null == entity) {
            return this.alipayClient;
        }
        DefaultAlipayClient client = clientMap.get(entity.getMerchantNo());
        if (null != client) {
            return client;
        } else {
            client = new DefaultAlipayClient(alipayConfiguration.getOpenApiDomain(), entity.getMerchantNo(), entity.getQdPayPriKey(),
                    FORMAT_JSON, CHARSET_UTF8, entity.getThirdPayPubKey(), SIGN_TYPE);
            client.setConnectTimeout(alipayConfiguration.getConnectTimeout());
            client.setReadTimeout(alipayConfiguration.getReadTimeout());
            clientMap.put(entity.getMerchantNo(), client);
            return client;
        }
    }

    @Override
    public PrepayStrategyResponse generatePayParams(PayType payType, PrepayStrategyReqVo req) {
        PrepayStrategyResponse response = new PrepayStrategyResponse();

        if (PayType.ALIPAY_APP.equals(payType)) {
            this.appPay(req, response);
        } else if (PayType.ALIPAY_H5.equals(payType)) {
            this.h5Pay(req, response);
        } else {
            throw new SystemException(ExceptionEnum.E20001, "支付宝支付方式不存在，paytype:".concat(payType.desc()));
        }
        return response;
    }

    /**
     * h5支付
     *
     * @param req
     * @param response
     * @return
     */
    public void h5Pay(PrepayStrategyReqVo req, PrepayStrategyResponse response) {
        ChannelMerchantInfoEntity entity = req.getChannelMerchantInfoEntity();
        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
        alipayRequest.setReturnUrl(req.getMerPageUrl());
        String notifyUrl = alipayConfiguration.getPayNotifyUrl();
        if (null != entity) {
            notifyUrl = notifyUrl + "/" + entity.getPayChannel() + "/" + entity.getBizCode() + "/" + entity.getMerchantNo();
        }
        alipayRequest.setNotifyUrl(notifyUrl);
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(req.getBizOrderNo());
        //设置5分钟后支付超时
        Date expireTime = new Date(req.getPayOrderCreateTime().getTime() + (6 * 60 * 1000));
        model.setSubject(req.getSubject());
        model.setTimeExpire(DateUtils.get(19, expireTime));
        model.setOutTradeNo(req.getBizOrderNo());
        model.setTotalAmount(AmountUtil.centToyuan(req.getPayAmount()));//支付宝单位元
        model.setPassbackParams(req.getAttach());
        model.setProductCode("QUICK_WAP_WAY");
        alipayRequest.setBizModel(model);
        try {
            //form方式唤起
            //AlipayTradeWapPayResponse wapPayResponse = alipayClient.pageExecute(alipayRequest);
            DefaultAlipayClient localClient = initClient(req.getChannelMerchantInfoEntity());
            //链接方式唤起
            AlipayTradeWapPayResponse wapPayResponse = localClient.pageExecute(alipayRequest, "GET");
            wapPayResponse.setOutTradeNo(req.getBizOrderNo());
            String generateParam = JSON.toJSONString(wapPayResponse);
            logger.info("支付宝h5预支付生成参数：{}", generateParam);
            if (!wapPayResponse.isSuccess()) {
                throw new SystemException(ExceptionEnum.E20002, "h5支付", wapPayResponse.getSubCode(), wapPayResponse.getSubMsg());
            }
            response.setPrepayReq(generateParam);
            response.setMWebUrl(wapPayResponse.getBody());
            response.setTradeStatus(TradeStatusEnum.SUCCESS);
        } catch (AlipayApiException e) {
            logger.error("支付宝h5预支付生成参数异常：", e);
            String code = Strings.isNullOrEmpty(e.getErrCode()) ? ExceptionEnum.E20001.name() : e.getErrCode();
            String msg = Strings.isNullOrEmpty(e.getErrMsg()) ? e.getMessage() : e.getErrMsg();
            throw new SystemException(ExceptionEnum.E20001, code, msg);
        } catch (Exception e) {
            logger.error("支付宝h5预支付生成参数异常：", e);
            throw new SystemException(ExceptionEnum.E10000);
        }

    }

    /**
     * 支付宝app支付
     *
     * @param req
     * @param response
     */
    private void appPay(PrepayStrategyReqVo req, PrepayStrategyResponse response) {
        ChannelMerchantInfoEntity entity = req.getChannelMerchantInfoEntity();
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setSubject(req.getSubject());
        //启用绝对超时时间：六分钟
        Date expireTime = new Date(req.getPayOrderCreateTime().getTime() + (6 * 60 * 1000));
        model.setTimeExpire(DateUtils.get(19, expireTime));
        model.setOutTradeNo(req.getChannelNo());
        model.setTotalAmount(AmountUtil.centToyuan(req.getPayAmount()));//支付宝单位元
        model.setPassbackParams(req.getAttach());
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        String notifyUrl = alipayConfiguration.getPayNotifyUrl();
        if (null != entity) {
            notifyUrl = notifyUrl + "/" + entity.getPayChannel() + "/" + entity.getBizCode() + "/" + entity.getMerchantNo();
        }
        request.setNotifyUrl(notifyUrl);
        try {
            DefaultAlipayClient localClient = initClient(req.getChannelMerchantInfoEntity());
            AlipayTradeAppPayResponse alipayTradeAppPayResponse = localClient.sdkExecute(request);
            alipayTradeAppPayResponse.setOutTradeNo(req.getChannelNo());
            String generateParam = JSON.toJSONString(alipayTradeAppPayResponse);
            logger.info("支付宝直连预支付生成参数：{}", generateParam);
            if (!alipayTradeAppPayResponse.isSuccess()) {
                throw new SystemException(ExceptionEnum.E20002, "app支付2.0", alipayTradeAppPayResponse.getSubCode(), alipayTradeAppPayResponse.getSubMsg());
            }
            response.setPrepayReq(generateParam);
            response.setPrepayOrderString(alipayTradeAppPayResponse.getBody());
            response.setTradeStatus(TradeStatusEnum.SUCCESS);
        } catch (AlipayApiException e) {
            logger.error("支付宝直连预支付生成参数异常：", e);
            String code = Strings.isNullOrEmpty(e.getErrCode()) ? ExceptionEnum.E20001.name() : e.getErrCode();
            String msg = Strings.isNullOrEmpty(e.getErrMsg()) ? e.getMessage() : e.getErrMsg();
            throw new SystemException(ExceptionEnum.E20001, code, msg);
        } catch (Exception e) {
            logger.error("支付宝直连预支付生成参数异常：", e);
            throw new SystemException(ExceptionEnum.E10000);
        }
    }


    @Override
    public PayQueryStrategyRespVo queryPayHttp(PayType payType, PayQueryStrategyReqVo request) {
        PayQueryStrategyRespVo response = new PayQueryStrategyRespVo();
        //封装支付宝查询请求实体
        AlipayTradeQueryRequest alipayRequest = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(0 == request.getThirdFlag() ? request.getBizOrderNo() : request.getChannelNo());

        alipayRequest.setBizModel(model);
        try {
            DefaultAlipayClient localClient = initClient(request.getChannelMerchantInfoEntity());
            logger.info("支付宝直连查询请求：{}", JSON.toJSONString(alipayRequest));
            AlipayTradeQueryResponse alipayTradeAppPayResponse = localClient.execute(alipayRequest);
            logger.info("支付宝直连查询返回：{}", JSON.toJSONString(alipayTradeAppPayResponse));
            //调用失败, 包含订单不存在
            if (!alipayTradeAppPayResponse.isSuccess()) {
                response.setErrCode(alipayTradeAppPayResponse.getSubCode());
                response.setErrMsg(alipayTradeAppPayResponse.getSubMsg());
                /** 支付宝状态特殊逻辑：创建时间在七分钟内查询 “交易不存在” 当做处理中处理， 其他当失败 */
                long orderTimeoutMils = request.getPayOrderCreateTime().getTime() + (7 * 60 * 1000);
                if ("ACQ.TRADE_NOT_EXIST".equals(alipayTradeAppPayResponse.getSubCode()) && new Date().getTime() < orderTimeoutMils) {
                    response.setChannelPayStatus(ChannelPayStatus.PROCESSING);
                } else {
                    response.setChannelPayStatus(ChannelPayStatus.FAIL);
                }
                return response;
            }
            //封装公共返回
            AliPayTradeStatusEnum statusEnum = AliPayTradeStatusEnum.getTradeStatusEnum(alipayTradeAppPayResponse.getTradeStatus());
            switch (statusEnum) {
                case TRADE_SUCCESS:
                case TRADE_FINISHED:
                    response.setChannelPayStatus(ChannelPayStatus.SUCCESS);
                    response.setQueryResp(JSON.toJSONString(alipayTradeAppPayResponse));
                    response.setFinishTime(alipayTradeAppPayResponse.getSendPayDate());
                    response.setThirdOrderNo(alipayTradeAppPayResponse.getTradeNo());
                    response.setBuyerId(alipayTradeAppPayResponse.getBuyerUserId());
                    response.setBuyerEmail(alipayTradeAppPayResponse.getBuyerLogonId());
                    response.setFeeAmount(alipayTradeAppPayResponse.getPayAmount());
                    break;
                case TRADE_CLOSED:
                    response.setChannelPayStatus(ChannelPayStatus.CLOSED);
                    break;
                case WAIT_BUYER_PAY:
                    response.setChannelPayStatus(ChannelPayStatus.PROCESSING);
                    break;
                default:
                    //异常状态
                    response.setChannelPayStatus(null);
                    break;
            }
            response.setErrCode(alipayTradeAppPayResponse.getSubCode());
            response.setErrMsg(alipayTradeAppPayResponse.getSubMsg());
        } catch (AlipayApiException e) {
            logger.error("支付宝直连订单查询异常：", e);
            String code = Strings.isNullOrEmpty(e.getErrCode()) ? ExceptionEnum.E20001.name() : e.getErrCode();
            String msg = Strings.isNullOrEmpty(e.getErrMsg()) ? e.getMessage() : e.getErrMsg();
            throw new SystemException(ExceptionEnum.E20001, code, msg);
        } catch (Exception e) {
            logger.error("支付宝直连订单查询异常：", e);
            //超时固定编码，请勿改动错误编码
            throw new SystemException(ExceptionEnum.E20001);
        }
        return response;
    }




}

